﻿using FluentData;
using GFluentCode.Tools;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;

namespace GFluentCode.ORM
{
    /// <summary>
    /// ORM基类
    /// </summary>
    public abstract class ORMBase
    {
        #region 数据连接对象

        /// <summary>
        /// 数据库类型
        /// </summary>
        public EnDbType DbType { get; protected set; }

        //private IDbContext _dbaser;
        /// <summary>
        /// Context
        /// </summary>
        public IDbContext DBaser
        {
            //get
            //{
            //    if (_dbaser == null)
            //        if (DbType.Equals(EnDbType.Sqlite))
            //            _dbaser = new DbContext().ConnectionStringName("conn", new SqliteProvider());
            //        else if (DbType.Equals(EnDbType.SqlServer))
            //            _dbaser = new DbContext().ConnectionStringName("conn", new SqlServerProvider());

            //        else throw new Exception("无指定的Provider");

            //    return _dbaser;
            //}

            //protected set { _dbaser = value; }
            get;
        }

        /// <summary>
        /// 被执行的Sql
        /// </summary>
        public string Sql { get; internal set; }

        /// <summary>
        /// 是否使用加密连接串
        /// </summary>
        public bool UseEncryptDbString { get; set; } = false;

        /// <summary>
        /// 数据库连接串
        /// 可修改解密方式（注意和自己的加密方式对应）
        /// </summary>
        public virtual string DbConnectString
        {
            get => DBaser.Data.ConnectionString;
            set
            {
                if (UseEncryptDbString)
                {
                    var key = value.Substring(0, 8);
                    var conn = value.Replace(key, "");
                    DBaser.Data.ConnectionString = DescEncryptHelper.Decrypt(conn, key);
                }
                else DBaser.Data.ConnectionString = value;
            }
        }
        #endregion

        #region 
        /// <summary>
        /// 根据配置文件生成
        /// </summary>
        public ORMBase(bool useEncryptDbString = false)
        {
            EnDbType dbType;
            var b = Enum.TryParse(AppConfigHelper.ReadItem("DbType"), out dbType);

            if (!b) throw new Exception("未指定数据库类型");

            UseEncryptDbString = useEncryptDbString;

            if (DbType.Equals(EnDbType.Sqlite))
                DBaser = new DbContext().ConnectionStringName("conn", new SqliteProvider());
            else if (DbType.Equals(EnDbType.SqlServer))
                DBaser = new DbContext().ConnectionStringName("conn", new SqlServerProvider());

            if (useEncryptDbString)
                DbConnectString = DBaser.Data.ConnectionString;

            DBaser.OnError(e =>
            {
                throw new Exception($"数据库错误：{e.Exception.Message},{e.Command.CommandText}");
            });
            DBaser.OnExecuting(e =>
            {
                Sql = e.Command.CommandText;
            });
        }

        /// <summary>
        /// 根据参数生成(不使用加密串)
        /// </summary>
        /// <param name="connectString"></param>
        /// <param name="dbType"></param>
        public ORMBase(string connectString, EnDbType dbType)
        {
            DbType = dbType;
            UseEncryptDbString = false;

            if (DbType.Equals(EnDbType.Sqlite))
                DBaser = new DbContext().ConnectionString(connectString, new SqliteProvider());
            else if (DbType.Equals(EnDbType.SqlServer))
                DBaser = new DbContext().ConnectionString(connectString, new SqlServerProvider());
            else throw new Exception("无指定的Provider");

            DbConnectString = connectString;
        }

        /// <summary>
        /// 根据参数生成
        /// </summary>
        /// <param name="connectString">连接串</param>
        /// <param name="useEncrypt">是否使用加密串</param>
        /// <param name="dbType"></param>
        public ORMBase(string connectString, bool useEncrypt, EnDbType dbType)
        {
            DbType = dbType;
            UseEncryptDbString = useEncrypt;

            if (DbType.Equals(EnDbType.Sqlite))
                DBaser = new DbContext().ConnectionString(connectString, new SqliteProvider());
            else if (DbType.Equals(EnDbType.SqlServer))
                DBaser = new DbContext().ConnectionString(connectString, new SqlServerProvider());
            else throw new Exception("无指定的Provider");

            DbConnectString = connectString;
        }
        #endregion

        #region Sql操作 方法受保护只能在子类中使用，不会开放到对象中

        /// <summary>
        /// 通过sql判断是否存在
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        protected bool ExistsBySql<T>(string sql) where T : class, new()
        {
            if (string.IsNullOrWhiteSpace(sql)) throw new Exception("未设置Sql");

            return DBaser.Sql(sql).QueryMany<T>().Count > 0;
        }

        /// <summary>
        /// 按sql查单个
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <returns></returns>
        protected T QuerySingleBySql<T>(string sql) where T : class, new()
        {
            if (string.IsNullOrWhiteSpace(sql)) throw new Exception("未设置Sql");

            return DBaser.Sql(sql).QuerySingle<T>();
        }

        /// <summary>
        /// 按sql语句查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <returns></returns>
        protected IList<T> QueryBySql<T>(string sql) where T : class, new()
        {
            if (string.IsNullOrWhiteSpace(sql)) throw new Exception("未设置Sql");

            return DBaser.Sql(sql).QueryMany<T>();
        }

        /// <summary>
        /// 表联查分页
        /// </summary>        
        /// <param name="tableName">表名，可以写联查表语句</param>
        /// <param name="fields">查询字段</param>
        /// <param name="where">where语句</param>
        /// <param name="order">排序字段</param>
        /// <param name="page">当前页</param>
        /// <param name="size">分页大小</param>
        /// <returns></returns>
        protected IList<T> QueryPage<T>(string tableName, string fields, string where, string order, int page, int size) where T : class, new()
        {
            return DBaser.Select<T>(fields)
                .From(tableName)
                .Where(where)
                .OrderBy(order)
                .Paging(page, size)
                .QueryMany();
        }
        #endregion

        #region 其它

        /// <summary>
        /// 事务式处理
        /// </summary>
        /// <param name="sqls"></param>
        /// <returns></returns>
        protected bool Transaction(List<string> sqls)
        {
            using (var db = DBaser.UseTransaction(true))
            {
                try
                {
                    foreach (var sql in sqls)
                    {
                        db.Sql(sql).Execute();
                    }

                    db.Commit();
                }
                catch (Exception ex)
                {
                    db.Rollback();
                    throw ex;
                }
            }
            return true;
        }

        /// <summary>
        /// 自定义逻辑的事务
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        protected bool Transaction(Action<IDbContext> func)
        {
            if (func is null) return false;

            using (var db = DBaser.UseTransaction(true))
            {
                try
                {

                    func(db);

                    db.Commit();
                }
                catch (Exception ex)
                {
                    db.Rollback();
                    throw ex;
                }
            }
            return true;
        }

        /// <summary>
        /// 执行sql语句
        /// </summary>
        /// <param name="sql"></param>
        protected void Execute(string sql)
        {
            DBaser.Sql(sql).Execute();
        }

        /// <summary>
        /// 执行sql语句,返回影响条数
        /// </summary>
        /// <param name="sql"></param>
        protected int ExecuteReturnCount(string sql)
        {
            return DBaser.Sql(sql).Execute();
        }

        /// <summary>
        /// 按sql查询返回DataTable
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        protected DataTable QueryDataTableBySql(string sql)
        {
            return DBaser.Sql(sql).QuerySingle<DataTable>();
        }
        #endregion
    }
}
